/*
 * AbstractBank.java
 *
 *
 */
package banksimulator.bank;

import javax.swing.event.EventListenerList;

/**
 * 银行抽象类，能够存放多个Account并可以进行遍历、移动，随机访问等操作。
 * @author Rajab
 */
public abstract class AbstractBank implements Iterable<AbstractAccount> {

    /**
     * 事件监视器列表,存放各个监听银行存放帐户变动情况的监听器。
     */
    protected EventListenerList listenerList = new EventListenerList();

    /**
     * 取得指定帐户ID的帐户。
     * @param accountID 要获取的帐户ID
     * @return 指定帐户ID的帐户
     * @throws NoSuchAccountException 如果指定帐户ID不存在
     */
    public abstract AbstractAccount getAccount(String accountID) throws NoSuchAccountException;

    /**
     * 获得指定索引处存放的帐户(可选)，如果实现此方法，则说明存放的帐户应该按某种顺序进行存放。
     * @param index 帐户的索引(从0开始计数)
     * @return 指定索引的帐户
     * @throws IndexOutOfBoundsException 指定的索引超出范围
     */
    public abstract AbstractAccount getAccount(int index) throws IndexOutOfBoundsException;

    /**
     * 获得当前存放的帐户个数。
     * @return 存放的帐户个数
     */
    public abstract int size();

    /**
     * 向银行中添加一个新的帐户。
     * <p><span>注意：</span> 实现此方法时应当调用fireBankChange方法以通知所有注册到当前
     * 银行的侦听器，此银行内存储的帐户已经发生变动。
     * <br>使用fireBankChange(accountID, BankChangeEvent.ChangeType.ADD);
     * 来通知已经向银行中<b添加了</b>一个帐户ID为accountID的帐户。
     * @param account 要添加的帐户
     */
    public abstract void addAccount(AbstractAccount account);

    /**
     * 从银行中移除指定的帐户。
     * <p><span>注意：</span> 实现此方法时应当调用fireBankChange方法以通知所有注册到当前
     * 银行的侦听器，此银行内存储的帐户已经发生变动。
     * <br>使用fireBankChange(accountID, BankChangeEvent.ChangeType.REMOVE);
     * 来通知已经向银行中<b删除</b>了一个帐户ID为accountID的帐户。
     * @param account 要移除的帐户
     * @throws NoSuchAccountException 如果银行中不存在该帐户
     */
    public abstract void removeAccount(AbstractAccount account) throws NoSuchAccountException;

    /**
     * 从银行中移除指定ID的帐户。
     * <p><span>注意：</span> 实现此方法时应当调用fireBankChange方法以通知所有注册到当前
     * 银行的侦听器，此银行内存储的帐户已经发生变动。
     * <br>使用fireBankChange(accountID, BankChangeEvent.ChangeType.REMOVE);
     * 来通知已经向银行中<b删除</b>了一个帐户ID为accountID的帐户。
     * @param accountID
     * @throws NoSuchAccountException 如果银行中不存在该帐户
     */
    public abstract void removeAccount(String accountID) throws NoSuchAccountException;

    /**
     * 银行中是否存在指定帐户。
     * @param account 要判断是否存在的帐户
     * @return 帐户是否存在
     */
    public abstract boolean isExists(AbstractAccount account);

    /**
     * 银行中是否存在指定ID的帐户。
     * @param accountID 要判断存在的帐户ID
     * @return　指定ID的帐户是否存在
     */
    public abstract boolean isExists(String accountID);

    /**
     *　获得当前银行的名称。
     * @return 银行的名称
     */
    public abstract String getName();

    /**
     *　注册一个银行帐户更改侦听器。
     * <p>通过注册该侦听器，可以在银行内的帐户发生增删变动变动时得到通知并执行某种操作,如：
     * <pre>
     * bank.addBankChangeListener(new BankChangeListener() {
     *       public void bankChanged(BankChangeEvent evt) {
     *           //处理代码
     *       }
     * });
     * </pre>
     * @param listener　要注册的银行帐户更改监听器
     */
    public void addBankChangeListener(BankChangeListener listener) {
        listenerList.add(BankChangeListener.class, listener);
    }

    /**
     * 移除一个银行帐户更改监听器。
     * @param listener 要移除的银行帐户更改监听器
     */
    public void removeBankChangeListener(BankChangeListener listener) {
        listenerList.remove(BankChangeListener.class, listener);
    }

    /**
     * 通知银行存储的帐户发生了变动。
     * @param accountID 发生变动的帐户ID
     * @param type 发生的变动情况，是添加帐户还是删除帐户
     */
    protected void fireBankChange(String accountID, BankChangeEvent.ChangeType type) {
        BankChangeEvent evt = new BankChangeEvent(this, accountID, type);
        for (Object listener : listenerList.getListenerList()) {
            if (listener instanceof BankChangeListener) {
                ((BankChangeListener) listener).bankChanged(evt);
            }
        }
    }
}
